package com.study.connect.service.impl;

import com.study.connect.handler.ByteToServiceInvokeDecoderHandler;
import com.study.connect.service.handler.InvokeServiceHandler;
import com.study.connect.handler.ServiceInvokeToByteEncoderHandler;
import com.study.connect.handler.InvokeResultToByteEncoderHandler;
import com.study.connect.service.IStartService;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.timeout.IdleStateHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

/**
 * @包名称 com.study.connect.service.impl
 * @类描述 <pre></pre>
 * @作者 zhangbo
 * @创建时间 2020/6/13.
 * @版本 1.00
 * @修改记录 <pre>
 *     版本           修改人         修改日期         修改内容描述
 *     -----------------------------------------------------------
 *     1.00           zhangbo        2020/6/13.           类创建
 *     -----------------------------------------------------------
 * </pre>
 */
@Slf4j
@Service
public class StartServiceImpl implements IStartService {

    @Autowired
    private BeanFactory beanFactory;

    @Override
    public void start(Integer port) {
        log.info("开始启动服务，端口号：{}", port);
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        ServerBootstrap server = new ServerBootstrap();
        try {
            server.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .handler(new LoggingHandler(LogLevel.INFO))
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            ChannelPipeline pipeline = socketChannel.pipeline();
                            /*LengthFieldBasedFrameDecoder参数含义：数据包最大长度，长度域的偏移量（0偏移表示长度域在包最前面），长度域占用的字节数（4个字节），要添加到长度字段值的补偿值，读取实际数据包的偏移量（跳过长度域）*/
                            pipeline.addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4, 0, 4))
                                    /*LengthFieldPrepender参数含义：前置长度字段所占的字节数*/
                                    .addLast(new LengthFieldPrepender(4))
                                    .addLast(new IdleStateHandler(5, 0, 0, TimeUnit.SECONDS))
                                    .addLast(new ByteToServiceInvokeDecoderHandler())
                                    .addLast(new ServiceInvokeToByteEncoderHandler())
                                    .addLast(new InvokeResultToByteEncoderHandler())
                                    .addLast(new InvokeServiceHandler(beanFactory));
                        }
                    });
            ChannelFuture future = server.bind(port).sync();
            future.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            log.error("线程中断:{}", e);
            Thread.currentThread().interrupt();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}
